using System;
using System.Data;
using System.Collections;
using System.Collections.Generic;

using Framework;

namespace SchemaMonitor
{
    [Serializable()]
    public partial class CImageMatchingList : List<CImageMatching>
    {
        #region Constructors
        //Basic constructor
        public CImageMatchingList() : base() {}
       
        //More efficient memory-allocation if size is known
        public CImageMatchingList(int capacity) : base(capacity) {}
        
        //Shares the index (if its already been computed)
        public CImageMatchingList(CImageMatchingList list) : base(list.Count)
        {
            foreach (CImageMatching i in list)
                base.Add(i);
        }

        //Generic list (eg. from paging control), have to assume type
        public CImageMatchingList(IList list) : base(list.Count)
        {
            foreach (CImageMatching i in list)
                base.Add(i);
        }
        #endregion

        #region Top/Bottom/Page
        public CImageMatchingList Top(int count)
        {
            if (count >= this.Count)
                return this;
            return Page(count, 0); 
        }
        public CImageMatchingList Bottom(int count)   
        {
            if (count > this.Count)
                count = this.Count;
            return new CImageMatchingList(this.GetRange(this.Count - count - 1, count));
        }
        public CImageMatchingList Page(int pageSize, int pageIndex)
        {
            return new CImageMatchingList( CUtilities.Page(this, pageSize, pageIndex) );
        }
        #endregion

        #region BulkEditLogic
        public bool HaveSameValue(string propertyName)               { return CReflection.HaveSameValue(this, propertyName); }
        public void SetSameValue( string propertyName, object value) {        CReflection.SetSameValue( this, propertyName, value); }
        #endregion

        #region SortBy
        //Public
        public CImageMatchingList SortBy(string propertyName) { return SortBy(propertyName, false); }
        public CImageMatchingList SortBy(string propertyName, bool descending)
        {
            CImageMatchingList copy = new CImageMatchingList(this);
            if (this.Count == 0)    return copy;
            copy.Sort(new CImageMatchingList_SortBy(propertyName, descending, this));
            return copy;
        }
        //Private 
        private class CImageMatchingList_SortBy : CReflection.GenericSortBy, IComparer<CImageMatching>
        {
            public CImageMatchingList_SortBy(string propertyName, bool descending, IList list) : base(propertyName, descending, list) { }
            public int Compare(CImageMatching x, CImageMatching y) { return base.Compare(x, y); }
        }
        #endregion

        #region SaveAll/DeleteAll
        //Use default connection (may be overridden in base class)
        public void SaveAll()   {   if (this.Count > 0) { SaveAll(  this[0].DataSrc);    }    }
        public void DeleteAll() {   if (this.Count > 0) { DeleteAll(this[0].DataSrc);    }    }

        //Use connection supplied
        public void SaveAll(  CDataSrc dataSrc) {   dataSrc.BulkSave(this);    }
        public void DeleteAll(CDataSrc dataSrc) {   dataSrc.BulkDelete(this);  }

        //Use transaction supplied
        public void SaveAll(  IDbTransaction txOrNull)    {   foreach (CImageMatching i in this) {   i.Save(  txOrNull);   }   }
        public void DeleteAll(IDbTransaction txOrNull)    {   foreach (CImageMatching i in this) {   i.Delete(txOrNull);   }   }

        //Use a specified isolation level
        public void SaveAll(  IsolationLevel txIsolationLevel)   {   if (this.Count > 0) { SaveAll(  this[0].DataSrc, txIsolationLevel);  }    }
        public void DeleteAll(IsolationLevel txIsolationLevel)   {   if (this.Count > 0) { DeleteAll(this[0].DataSrc, txIsolationLevel);  }    }

        //Use a specified connection and isolation level
        public void SaveAll(  CDataSrc dataSrc, IsolationLevel txIsolationLevel)   {   dataSrc.BulkSave(  this, txIsolationLevel);  }
        public void DeleteAll(CDataSrc dataSrc, IsolationLevel txIsolationLevel)   {   dataSrc.BulkDelete(this, txIsolationLevel);  }
        #endregion
        
        #region Cache-Control
        public new void Add(CImageMatching item)
        {
            if (null != _index)
            {
                string k = Key(item.MD5, item.MatchingMd5);
                if (! _index.ContainsKey(k))
                    _index[k] = item;
            }
            base.Add(item);
        }
        public new void Remove(CImageMatching item)
        {
            if (null != _index)
            {
                string k = Key(item.MD5, item.MatchingMd5);
                if (_index.ContainsKey(k))
                    _index.Remove(k);
            }
            base.Remove(item);
        }
    
        //Supplementary List Overloads
        public void Add(   IList<CImageMatching> itemsToAdd)    {   foreach (CImageMatching i in itemsToAdd)   { Add(   i); }   }
        public void Remove(IList<CImageMatching> itemsToRemove) {   foreach (CImageMatching i in itemsToRemove){ Remove(i); }   }
        #endregion  

        #region Main Index (on MD5, MatchingMd5)
        public CImageMatching GetById(Guid mD5, Guid matchingMd5)
        {
            CImageMatching c = null;
            string k = Key(mD5, matchingMd5);
            Index.TryGetValue(k, out c);
            return c;
        }
        public static string Key(Guid mD5, Guid matchingMd5)
        {
            return String.Concat(mD5, "_", matchingMd5);
        }

        [NonSerialized]
        private Dictionary<string,CImageMatching> _index;
        private Dictionary<string,CImageMatching> Index
        {
            get    
            {
                if (null != _index)
                    if (_index.Count == this.Count)
                        return _index;

                _index = new Dictionary<string,CImageMatching>(this.Count);
                foreach (CImageMatching i in this)
                    _index[ Key(i.MD5, i.MatchingMd5) ] = i;
                return _index;
             }
        }
        #endregion
            
        #region Foreign-Key Indices (Subsets)
        //Index by MD5
        public CImageMatchingList GetByMD5(Guid mD5)
        {
            CImageMatchingList temp = null;
            if (! IndexByMD5.TryGetValue(mD5, out temp))
            {
                temp = new CImageMatchingList();
                IndexByMD5[mD5] = temp;
            }
            return temp;
        }

        [NonSerialized]
        private Dictionary<Guid, CImageMatchingList> _indexByMD5;
        private Dictionary<Guid, CImageMatchingList> IndexByMD5
        {
            get
            {
                if (null == _indexByMD5)
                {
                    Dictionary<Guid, CImageMatchingList> index = new Dictionary<Guid, CImageMatchingList>();
                    CImageMatchingList temp = null;
                    foreach (CImageMatching i in this)
                    {
                        if (! index.TryGetValue(i.MD5, out temp))
                        {
                            temp = new CImageMatchingList();
                            index[i.MD5] = temp;
                        }
                        temp.Add(i);
                    }
                    _indexByMD5 = index;
                }
                return _indexByMD5;
            }
        }
        //Index by MatchingMd5
        public CImageMatchingList GetByMatchingMd5(Guid matchingMd5)
        {
            CImageMatchingList temp = null;
            if (! IndexByMatchingMd5.TryGetValue(matchingMd5, out temp))
            {
                temp = new CImageMatchingList();
                IndexByMatchingMd5[matchingMd5] = temp;
            }
            return temp;
        }

        [NonSerialized]
        private Dictionary<Guid, CImageMatchingList> _indexByMatchingMd5;
        private Dictionary<Guid, CImageMatchingList> IndexByMatchingMd5
        {
            get
            {
                if (null == _indexByMatchingMd5)
                {
                    Dictionary<Guid, CImageMatchingList> index = new Dictionary<Guid, CImageMatchingList>();
                    CImageMatchingList temp = null;
                    foreach (CImageMatching i in this)
                    {
                        if (! index.TryGetValue(i.MatchingMd5, out temp))
                        {
                            temp = new CImageMatchingList();
                            index[i.MatchingMd5] = temp;
                        }
                        temp.Add(i);
                    }
                    _indexByMatchingMd5 = index;
                }
                return _indexByMatchingMd5;
            }
        }

        #endregion


    }
}